package com.zg.scf.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zg.common.core.dao.auth.*;
import com.zg.common.core.dao.scf.CompanyDao;
import com.zg.common.core.dao.scf.ScfRoleExtDao;
import com.zg.common.core.dao.scf.ScfUserCompanyDao;
import com.zg.common.core.dao.scf.entity.Company;
import com.zg.common.core.dao.scf.entity.ScfRoleExt;
import com.zg.common.core.dao.scf.entity.ScfUserCompany;
import com.zg.common.core.exception.BusinessException;
import com.zg.common.web.Req;
import com.zg.scf.enm.UserTypeEnum;
import com.zg.scf.service.ScfMenuService;
import com.zg.scf.util.DataScopeUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class ScfMenuServiceImpl implements ScfMenuService {

    private final AuthRoleDao authRoleDao;
    private final AuthRoleMenuDao authRoleMenuDao;
    private final AuthMenuDao authMenuDao;
    private final ScfRoleExtDao scfRoleExtDao;
    private final DataScopeUtil dataScopeUtil;
    private final CompanyDao companyDao;
    private final AuthUserDao authUserDao;
    private final AuthRoleUserDao authRoleUserDao;
    private final ScfUserCompanyDao scfUserCompanyDao;

    @Override
    public List<AuthMenu> listAuthMenu(Long roleId) {
        AuthRole authRole = authRoleDao.getById(roleId);
        if (authRole == null) {
            BusinessException.happen("请选择正确的角色");
        }
        List<ScfRoleExt> scfRoleExtList = scfRoleExtDao.list(
                new LambdaQueryWrapper<ScfRoleExt>()
                        .eq(ScfRoleExt::getRoleId, roleId)
        );
        if (scfRoleExtList.size() != 1) {
            BusinessException.happen("角色配置错误");
        }
        ScfRoleExt scfRoleExt = scfRoleExtList.get(0);

        String currUserType = Req.getCurrUser().getType();
        boolean isSystemUser = UserTypeEnum.SYSTEM.getCode().equals(currUserType);
        if (!isSystemUser) {
            Long orgDataScope = dataScopeUtil.getOrgDataScope();
            if (!orgDataScope.equals(scfRoleExt.getCompanyId())) {
                BusinessException.happen("没有该数据的操作权限");
            }
        } else {
            Long companyId = scfRoleExt.getCompanyId();
            if (companyId == null) {
                List<AuthMenu> list = authMenuDao.list(
                        new LambdaQueryWrapper<AuthMenu>()
                                .eq(AuthMenu::getIsUse, true)
                );
                return toTree(list);
            }
        }

        List<Long> roleIds = getRoleIdsByCompanyId(scfRoleExt.getCompanyId());

        List<AuthMenu> authMenuList = getMenuByRoleIds(roleIds);

        return toTree(authMenuList);
    }

    private List<Long> getRoleIdsByCompanyId(Long companyId) {
        Company company = companyDao.getById(companyId);
        if (company == null) {
            BusinessException.happen("未找到所属企业");
        }

        List<ScfRoleExt> roleExtList = scfRoleExtDao.list(
                new LambdaQueryWrapper<ScfRoleExt>()
                        .eq(ScfRoleExt::getType, company.getCompanyType())
                        .eq(ScfRoleExt::getAuthStatus, company.getAuthStatus())
                        .eq(company.getEnLevelId() != null, ScfRoleExt::getEnLevelId, company.getEnLevelId())
                        .isNull(ScfRoleExt::getCompanyId)
        );
        if (roleExtList.isEmpty()) {
            return new ArrayList<>();
        }
        return roleExtList.stream().map(ScfRoleExt::getRoleId).collect(Collectors.toList());
    }

    @Override
    public List<AuthMenu> listByUserId(Long userId) {
        AuthUser authUser = authUserDao.getById(userId);
        if (authUser == null) {
            BusinessException.happen("未找到用户信息");
        }

        List<AuthRoleUser> authRoleUserList = authRoleUserDao.list(
                new LambdaQueryWrapper<AuthRoleUser>()
                        .eq(AuthRoleUser::getUserId, userId)
        );
        if (authRoleUserList.isEmpty()) {
            return new ArrayList<>();
        }
        List<Long> roleIds = authRoleUserList.stream().map(AuthRoleUser::getRoleId).collect(Collectors.toList());

        List<AuthMenu> authMenuList = getMenuByRoleIds(roleIds);

        String type = authUser.getType();
        if (!UserTypeEnum.SYSTEM.getCode().equals(type)) {
            List<ScfUserCompany> userCompanyList = scfUserCompanyDao.list(
                    new LambdaQueryWrapper<ScfUserCompany>()
                            .eq(ScfUserCompany::getUserId, userId)
            );
            if (userCompanyList.size() != 1) {
                BusinessException.happen("未找到用户与企业的关联关系");
            }
            ScfUserCompany scfUserCompany = userCompanyList.get(0);

            roleIds = getRoleIdsByCompanyId(scfUserCompany.getCompanyId());

            List<AuthMenu> companyMenuList = getMenuByRoleIds(roleIds);
            if (companyMenuList.isEmpty()) {
                return new ArrayList<>();
            }
            Map<Long, AuthMenu> companyMenuMap = companyMenuList.stream()
                    .collect(Collectors.toMap(AuthMenu::getId, Function.identity()));
            List<AuthMenu> list = authMenuList.stream()
                    .filter(m -> companyMenuMap.containsKey(m.getId())).collect(Collectors.toList());
            return toTree(list);
        }
        return toTree(authMenuList);
    }

    private List<AuthMenu> getMenuByRoleIds(List<Long> roleIds) {
        if (roleIds.isEmpty()) {
            return new ArrayList<>();
        }

        List<AuthRole> authRoleList = authRoleDao.list(
                new LambdaQueryWrapper<AuthRole>()
                        .in(AuthRole::getId, roleIds)
        );
        if (authRoleList.isEmpty()) {
            return new ArrayList<>();
        }
        roleIds = authRoleList.stream().map(AuthRole::getId).collect(Collectors.toList());

        List<AuthRoleMenu> authRoleMenuList = authRoleMenuDao.list(
                new LambdaQueryWrapper<AuthRoleMenu>()
                        .in(AuthRoleMenu::getRoleId, roleIds)
        );
        if (authRoleMenuList.isEmpty()) {
            return new ArrayList<>();
        }
        List<Long> menuIds = authRoleMenuList.stream().map(AuthRoleMenu::getMenuId).collect(Collectors.toList());

        return authMenuDao.list(
                new LambdaQueryWrapper<AuthMenu>()
                        .eq(AuthMenu::getIsUse, true)
                        .in(AuthMenu::getId, menuIds)
        );
    }

    private List<AuthMenu> toTree(List<AuthMenu> authMenuList) {
        List<AuthMenu> tree = new ArrayList<>();
        if (authMenuList == null || authMenuList.isEmpty()) {
            return tree;
        }

        Map<Long, AuthMenu> authMenuMap = new HashMap<>();
        for (AuthMenu authMenu : authMenuList) {
            authMenuMap.put(authMenu.getId(), authMenu);
        }
        for (AuthMenu authMenu : authMenuList) {
            Long pid = authMenu.getPid();
            if (pid == null) {
                tree.add(authMenu);
            } else {
                AuthMenu pAuthMenu = authMenuMap.get(pid);
                if (pAuthMenu != null) {
                    if (pAuthMenu.getChildren() == null) {
                        pAuthMenu.setChildren(new ArrayList<>());
                    }
                    pAuthMenu.getChildren().add(authMenu);
                } else {
                    tree.add(authMenu);
                }
            }
        }
        return tree;
    }
}
